package com.yonyou.brigade.third_parties.didi.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yonyou.brigade.basic_init.enums.ChannelEnum;
import com.yonyou.brigade.order_center.service.IBriOrderService;
import com.yonyou.brigade.third_parties.didi.model.DiDiConfig;
import com.yonyou.brigade.third_parties.didi.model.third.DiDiOrderDTO;
import com.yonyou.brigade.third_parties.didi.service.IDiDiOrderService;
import com.yonyou.brigade.third_parties.didi.util.DESUtil;
import com.yonyou.brigade.third_parties.didi.util.DiDiConstants;
import com.yonyou.brigade.third_parties.didi.util.DiDiRMIUtils;
import com.yonyou.brigade.third_parties.didi.util.DiDiResultUtil;
import com.yonyou.brigade.util.operateutil.DateUtils;
import com.yonyou.brigade.ybz.service.IConvertService;
import com.yonyou.ybzboot.starter.mongodb.dao.IMongoDao;
import com.yonyou.ybzboot.starter.mongodb.model.CriteriaMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 滴滴订单服务 实现类
 *
 * @author unknown
 */
@Service
@Slf4j
public class DiDiOrderServiceImpl implements IDiDiOrderService {

    @Autowired
    private DiDiRMIUtils diDiRMIUtils;

    @Autowired
    @Qualifier("convertServiceImpl")
    private IConvertService convertService;

    @Autowired
    @Qualifier("briOrderServiceImpl")
    private IBriOrderService briOrderService;

    @Value("${didi.tradeCarType}")
    private String diDiCarTradeType;

    @Value("${cnv.baigade.system.code}")
    private String systemCode;

    @Value("${cnv.register.userId}")
    private String cnvRegisterUserId;

    @Value("${cnv.register.tenant}")
    private String cnvRegisterTenant;

    @Value("${cnv.register.cookie}")
    private String cnvRegisterCookie;

    @Autowired
    private IMongoDao mongoDao;

    private int ddOrderLength = 50;

    /**
     * 支付方式是个人垫付、混合支付
     */
    private final ArrayList<Integer> invoicePayType = new ArrayList<>(Arrays.asList(1, 2));
    /**
     * 用车方式是专车、快车、豪华车
     */
    private final ArrayList<Integer> invoiceUseCarType = new ArrayList<>(Arrays.asList(2, 3, 5));

    /**
     * 拉取滴滴订单
     *
     * @param diDiConfig 配置信息
     * @param fetchDate  拉取日期
     * @param tenant     租户
     * @param channelId  渠道ID
     */
    @Override
    public void getDiDiOrderList(DiDiConfig diDiConfig, String fetchDate, String tenant, int channelId) {
        fetchOrders(0, ddOrderLength, diDiConfig, fetchDate, tenant, channelId);
    }

    @Override
    public List queryDiDiOrderWithDate(String start, String end, Integer payType, DiDiConfig diDiConfig, String phone) {
        Date startDate = DateUtils.str2Date(start, DateUtils.DD_DATE_FORMAT);

        JSONArray records = new JSONArray();
        //临时查询结束时间
        Date middleEndDate = DateUtils.str2Date(end, DateUtils.DD_DATE_FORMAT);
        //每次只能查询七天内的订单
        Date day7BeforeTempEnd = DateUtils.plusDay(middleEndDate, -6);
        while (day7BeforeTempEnd.after(startDate)) {
            records.addAll(queryDiDiOrderWithDateAndPage(DateUtils.date2Str(day7BeforeTempEnd, DateUtils.DD_DATE_FORMAT), DateUtils.date2Str(middleEndDate, DateUtils.DD_DATE_FORMAT), 0, 100, payType, diDiConfig, phone));
            middleEndDate = DateUtils.plusDay(day7BeforeTempEnd, -1);
            day7BeforeTempEnd = DateUtils.plusDay(day7BeforeTempEnd, -7);
        }
        middleEndDate = DateUtils.plusDay(day7BeforeTempEnd, 6);
        if (middleEndDate.after(startDate)) {
            records.addAll(queryDiDiOrderWithDateAndPage(start, DateUtils.date2Str(middleEndDate, DateUtils.DD_DATE_FORMAT), 0, 100, payType, diDiConfig, phone));
        }
        //最后只留下支付方式是个人垫付、混合支付，用车方式是专车、快车、豪华车，未开票的订单记录
        ArrayList<DiDiOrderDTO> result = new ArrayList<>();
        for (int i = 0; i < records.size(); i++) {
            JSONObject order = records.getJSONObject(i);
            if (invoicePayType.contains(order.getInteger(DiDiConstants.KEY_PAY_TYPE)) && invoiceUseCarType.contains(order.getInteger(DiDiConstants.KEY_USE_CAR_TYPE))) {
                result.add(JSON.parseObject(JSON.toJSONString(order), DiDiOrderDTO.class));
            }
        }
        return result;
    }

    private JSONArray queryDiDiOrderWithDateAndPage(String start, String end, Integer offset, Integer length, Integer payType, DiDiConfig diDiConfig, String phone) {
        Map<String, Object> orderParamsMap = generateGetOrderParamsMap(start, end, offset, length, payType, diDiConfig, phone);
        String responseOrders = diDiRMIUtils.executeRMIRequest(DiDiConstants.METHOD_GET_ORDERQUERY, orderParamsMap, "GET");
        JSONObject data = (JSONObject) DiDiResultUtil.handleResult(responseOrders, JSONObject.class);
        JSONArray partRecords = data.getJSONArray("records");
        JSONArray result = new JSONArray(partRecords);
        //如果一周内订单超过100条则继续取之后的数据
        while (partRecords.size() == length) {
            offset += length;
            partRecords = queryDiDiOrderWithDateAndPage(start, end, offset, length, payType, diDiConfig, phone);
            result.addAll(partRecords);
        }
        return result;
    }

    @Override
    public String getPersonOrderPage(DiDiConfig diDiConfig, String phone) {
        Map<String, Object> orderParamsMap = generateTicketParamsMap(diDiConfig, phone);

        Map<String, Object> params = new HashMap<>();
        params.put(DiDiConstants.KEY_CLIENT_ID, diDiConfig.getClientId());
        try {
            params.put("data_encode", DESUtil.encrypt(JSON.toJSONString(orderParamsMap), diDiConfig.getSignKey().substring(0, 8)));
        } catch (Exception e) {
            e.printStackTrace();
        }

        String responseOrders = diDiRMIUtils.executeRMIRequest(DiDiConstants.METHOD_GET_TICKET, params, "GET");
        return responseOrders;
    }

    private Map<String, Object> generateTicketParamsMap(DiDiConfig diDiConfig, String phone) {
        Map<String, Object> paramsMap = new HashMap<String, Object>();
        diDiRMIUtils.getToken(diDiConfig);
        paramsMap.put(DiDiConstants.KEY_CLIENT_ID, diDiConfig.getClientId());
        paramsMap.put(DiDiConstants.KEY_CLIENT_SECRET, diDiConfig.getClientSecret());
        paramsMap.put(DiDiConstants.KEY_COMPANY_ID, diDiConfig.getCompanyId());
        paramsMap.put("master_phone", diDiConfig.getPhone());
        paramsMap.put(DiDiConstants.KEY_PHONE, phone);
        paramsMap.put("scope", 0);
        return paramsMap;
    }

    /**
     * 按叫车人手机号、日期（支付时间、退款时间、个人支付转个人垫付时间）、支付方式查询
     * 开票的话需要之后过滤掉企业支付，以及出租车和代驾
     *
     * @param start      开始日期
     * @param end        结束日期
     * @param payType    支付方式
     * @param diDiConfig 配置信息
     * @param phone      电话号码
     * @return 查询参数
     */
    private Map<String, Object> generateGetOrderParamsMap(String start, String end, Integer offset, Integer length, Integer payType, DiDiConfig diDiConfig, String phone) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put(DiDiConstants.KEY_CLIENT_ID, diDiConfig.getClientId());
        paramsMap.put(DiDiConstants.KEY_ACCESS_TOKEN, diDiRMIUtils.getToken(diDiConfig));
        paramsMap.put(DiDiConstants.KEY_TIMESTAMP, System.currentTimeMillis());
        paramsMap.put(DiDiConstants.KEY_COMPANY_ID, diDiConfig.getCompanyId());

        paramsMap.put(DiDiConstants.KEY_CALL_PHONE, phone);
        paramsMap.put(DiDiConstants.KEY_START_DATE, start);
        paramsMap.put(DiDiConstants.KEY_END_DATE, end);
        paramsMap.put(DiDiConstants.KEY_IS_INVOICE, 0);
        if (!StringUtils.isEmpty(payType)) {
            paramsMap.put(DiDiConstants.KEY_PAY_TYPE, payType);
        }
        paramsMap.put(DiDiConstants.KEY_OFFSET, offset);
        paramsMap.put(DiDiConstants.KEY_LENGTH, length);

        Map<String, Object> orderParamsMap = diDiRMIUtils.keySort(paramsMap, diDiConfig);
        String sign = diDiRMIUtils.concatRequestParamsAndMd5Encode(orderParamsMap);
        orderParamsMap.put(DiDiConstants.KEY_SIGN, sign);
        return orderParamsMap;
    }


    private void fetchOrders(int offset, int length, DiDiConfig diDiConfig, String fetchDate, String tenant, int channelId) {

        Map<String, Object> orderParamsMap = generateFetchOrdersParamsMap(offset, length, diDiConfig, fetchDate);
        String responseOrders = diDiRMIUtils.executeRMIRequest(DiDiConstants.METHOD_GET_ORDERQUERY, orderParamsMap, "GET");
        JSONObject jsonObject = JSON.parseObject(responseOrders);
        int errno = jsonObject.getInteger("errno");
        String errmsg = jsonObject.getString("errmsg");
        if ("SUCCESS".equals(errmsg) && 0 == errno) {
            JSONObject data = jsonObject.getJSONObject("data");
            int total = data.getInteger("total");
            if (total > 0) {
                JSONArray records = data.getJSONArray("records");
                if (records != null && records.size() > 0) {
                    for (int i = 0; i < records.size(); i++) {
                        JSONObject record = records.getJSONObject(i);
                        String callPhone = record.getString("call_phone");
                        String orderId = record.getString("order_id");
                        Map<String, Object> orderDetailParamsMap = generateFetchOrderDetailParamsMap(orderId, diDiConfig);
                        String responseOrderDetail = diDiRMIUtils.executeRMIRequest(DiDiConstants.METHOD_GET_ORDERDETAILQUERY, orderDetailParamsMap, "GET");
                        JSONObject detailJson = JSON.parseObject(responseOrderDetail);
                        Integer errno1 = detailJson.getInteger("errno");
                        String errmsg1 = detailJson.getString("errmsg");
                        if ("SUCCESS".equals(errmsg1) && 0 == errno1) {
                            JSONObject detail = detailJson.getJSONObject("data");
                            if (detail != null) {
                                record.put("detail", detail);
                                dealWithMongo(orderId, DiDiConstants.CAR_MONGO_ORDER_TABLENAME, record);
                                JSONObject res = convertService.convert(diDiCarTradeType, systemCode, cnvRegisterUserId, cnvRegisterTenant, cnvRegisterCookie, record);
                                if (res != null && res.size() > 0 && res.getBoolean("success")) {
                                    JSONArray results = res.getJSONArray("result");
                                    if (results != null && results.size() > 0) {
                                        for (int j = 0; j < results.size(); j++) {
                                            JSONObject result = results.getJSONObject(j);
                                            JSONObject orderCenter = JSON.parseObject(result.getString("data"));
                                            if (orderCenter != null && orderCenter.size() > 0) {
                                                saveOrders(orderCenter, orderId, tenant, callPhone, channelId);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (total >= ddOrderLength && data.getJSONArray("records").size() >= ddOrderLength) {
                offset = offset + ddOrderLength;
                fetchOrders(offset, ddOrderLength, diDiConfig, fetchDate, tenant, channelId);
            }
        }
    }

    private Map<String, Object> generateFetchOrderDetailParamsMap(String orderId, DiDiConfig diDiConfig) {
        Map<String, Object> paramsMap = new HashMap<String, Object>();
        paramsMap.put(DiDiConstants.KEY_CLIENT_ID, diDiConfig.getClientId());
        paramsMap.put(DiDiConstants.KEY_ACCESS_TOKEN, diDiRMIUtils.getToken(diDiConfig));
        paramsMap.put(DiDiConstants.KEY_TIMESTAMP, System.currentTimeMillis());
        paramsMap.put(DiDiConstants.KEY_COMPANY_ID, diDiConfig.getCompanyId());
        paramsMap.put(DiDiConstants.KEY_ORDER_ID, orderId);
        Map<String, Object> orderParamsMap = diDiRMIUtils.keySort(paramsMap, diDiConfig);
        String sign = diDiRMIUtils.concatRequestParamsAndMd5Encode(orderParamsMap);
        orderParamsMap.put(DiDiConstants.KEY_SIGN, sign);
        return orderParamsMap;
    }

    private void saveOrders(JSONObject jsonObject, String orderId, String tenant, String callPhone, int channelId) {
        briOrderService.saveCar(jsonObject, orderId, tenant, callPhone, ChannelEnum.DIDI.getName(), channelId);
    }


    private Map<String, Object> generateFetchOrdersParamsMap(int offset, int length, DiDiConfig diDiConfig, String fetchDate) {
        Map<String, Object> paramsMap = new HashMap<String, Object>();
        paramsMap.put(DiDiConstants.KEY_CLIENT_ID, diDiConfig.getClientId());
        paramsMap.put(DiDiConstants.KEY_ACCESS_TOKEN, diDiRMIUtils.getToken(diDiConfig));
        paramsMap.put(DiDiConstants.KEY_TIMESTAMP, System.currentTimeMillis());
        paramsMap.put(DiDiConstants.KEY_COMPANY_ID, diDiConfig.getCompanyId());
        paramsMap.put(DiDiConstants.KEY_START_DATE, fetchDate);
        //jzf
        paramsMap.put(DiDiConstants.KEY_END_DATE, fetchDate);
        paramsMap.put(DiDiConstants.KEY_OFFSET, offset);
        paramsMap.put(DiDiConstants.KEY_LENGTH, length);
        Map<String, Object> orderParamsMap = diDiRMIUtils.keySort(paramsMap, diDiConfig);
        String sign = diDiRMIUtils.concatRequestParamsAndMd5Encode(orderParamsMap);
        orderParamsMap.put(DiDiConstants.KEY_SIGN, sign);
        return orderParamsMap;
    }

    private void dealWithMongo(String orderId, String mongoName, JSONObject orderJson) {
        CriteriaMap criteriaMap = new CriteriaMap();
        criteriaMap.put("order_id", orderId);
        List<JSONObject> orderSources = mongoDao.findByMap(criteriaMap, JSONObject.class, mongoName);
        if (orderSources != null && orderSources.size() > 0) {
            mongoDao.deleteByMap(criteriaMap, mongoName);
            mongoDao.getMongoTemplate().save(orderJson, mongoName);
        } else {
            mongoDao.getMongoTemplate().insert(orderJson, mongoName);
        }
    }

}
